package util

import (
	"gitee.com/gopher2011/mall/app/dao"
	"github.com/dgrijalva/jwt-go"
	"math/rand"
	"time"
)

/* 实现思路:
1、指定加密密钥
2、指定被保存在token中的实体对象，Claims 结构体。需要内嵌jwt.StandardClaims。这个结构体是用来保存信息的。
3、根据数据产生token：根据传入的信息，组装成一个Claims结构体对象，再从对象中获取token。
4、根据token解析数据：解析出token所对应的interface{}，再使用断言解析出Claims对象，取数据
*/
var (
	Secret []byte                          // 指定加密密钥
	Expire = time.Now().Add(3 * time.Hour) //设置token有效时间，当前时间 3 小时后。
	Issued = "mall"                        // token发行人
)

//Claim是一些实体（通常指的用户）的状态和额外的元数据
type Claims struct {
	p dao.UmsJWTParma
	jwt.StandardClaims
}

// 根据用户的用户名和密码产生token
func GenerateToken(u dao.UmsJWTParma) (string, error) {
	claims := Claims{
		p: u,
		StandardClaims: jwt.StandardClaims{
			// 过期时间
			ExpiresAt: Expire.Unix(),
			// 指定token发行人
			Issuer: "gin-blog",
		},
	}
	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	secret := RandStr(10)
	//该方法内部生成签名字符串，再用于获取完整、已签名的token
	token, err := tokenClaims.SignedString(secret)
	Secret = []byte(secret)
	return token, err
}

// 根据传入的token值获取到Claims对象信息，（进而获取其中的用户信息）
func ParseToken(token string) (*Claims, error) {

	//用于解析鉴权的声明，方法内部主要是具体的解码和校验的过程，最终返回*Token
	tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return Secret, nil
	})

	if tokenClaims != nil {
		// 从tokenClaims中获取到Claims对象，并使用断言，将该对象转换为我们自己定义的Claims
		// 要传入指针，项目中结构体都是用指针传递，节省空间。
		if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
			return claims, nil
		}
	}
	return nil, err
}

func RefreshHeadToken(oldToken string) (string, error) {
	claims, err := ParseToken(oldToken)
	if err != nil {
		return "", err
	}
	u := claims.p
	return GenerateToken(u)
}

// 生成随机字符串
func RandStr(len int) string {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	bytes := make([]byte, len)
	for i := 0; i < len; i++ {
		b := r.Intn(26) + 65
		bytes[i] = byte(b)
	}
	return string(bytes)
}

// 生成随机数字
func RandomInt(start int, end int) int {
	rand.Seed(time.Now().UnixNano())
	random := rand.Intn(end - start)
	random = start + random
	return random
}
